﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using CustomNetworking;

namespace Boggle
{
    //event handler delegates
    public delegate void GameStartedHandler(object sender, StringEventArgs e);
    public delegate void GameStoppedHandler(object sender, StringEventArgs e);
    public delegate void GameEndedHandler(object sender, EventArgs e);
    public delegate void TimeChangedHandler(object sender, StringEventArgs e);
    public delegate void ScoreChangedHandler(object sender, StringEventArgs e);
    public delegate void TerminatedHandler(object sender, EventArgs e);
    public delegate void IgnoringHandler(object sender, StringEventArgs e);

    public delegate void MessageSentHandler(object sender, StringEventArgs e);
    
    public class BoggleConnector
    {
        StringSocket socket;
        TcpClient client;
        ManualResetEvent connectDone = new ManualResetEvent(false);
        bool waitingForGame = true;

        // events
        public event GameStartedHandler GameStarted;
        public event GameEndedHandler ConnectionClosed;
        public event GameStoppedHandler GameStopped;
        public event TimeChangedHandler TimeChanged;
        public event ScoreChangedHandler ScoreChanged;
        public event TerminatedHandler Terminated;
        public event IgnoringHandler Ignored;

        public event MessageSentHandler MessageSent;

        // member variables
        int score1, score2, time;
        string  name, opponentName, board;

        public BoggleConnector(string n)
        {
            name = n;
            client = new TcpClient();
        }

        public void ConnectToServer()
        {
            connectDone.Reset();

            client.BeginConnect("localhost", 2000, ConnectionAccepted, client);

            connectDone.WaitOne(5000);

            Console.WriteLine("connected");

            socket = new StringSocket(client.Client, new UTF8Encoding());

            socket.BeginReceive(ReceiveCallback, null);

            string playMsg = "PLAY " + name + "\n";
            socket.BeginSend(playMsg, SendCallback, playMsg);
        }

        private void ConnectionAccepted(IAsyncResult result)
        {
            connectDone.Set();
        }

        private void CancelConnection()
        {
            if (!waitingForGame)
            {
                socket.CloseSocket(5);
            }
        }

        private void CloseConnection()
        {
            socket.CloseSocket(5);
        }


        private void SendCallback(Exception ex, object p)
        {
            if (MessageSent != null)
            { 
                MessageSent(this, new StringEventArgs((string)p));
            }
        }

        private void OnMessageSent(string s)
        {
            if (MessageSent != null)
            { 
                MessageSent(this, new StringEventArgs(s));
            }
        }

        private void ReceiveCallback(String s, Exception ex, object p)
        {
            try
            {
                if (s != null)
                {
                    socket.BeginReceive(ReceiveCallback, null);                    

                    // process the message
                    if (s.Substring(0, 5) == "TIME ")
                    {
                        OnTime(s.Substring(5));
                    }
                    else if (s.Substring(0, 6) == "SCORE ")
                    {
                        OnScoreChanged(s.Substring(6));
                    }
                    else if (s.Substring(8) == "IGNORING ")
                    {
                        OnIgnoring(s.Substring(8));
                    }
                    else if (s.Substring(0, 6) == "START ")
                    {
                        OnStart(s.Substring(6));
                    }
                    else if (s.Substring(0, 5) == "STOP ")
                    {
                        OnStop(s.Substring(5));
                    }
                    else if (s == "TERMINATED")
                    {
                        OnTerminated();
                    }
                }
                else
                {
                    OnConnectionClosed();
                }
            }
            catch (Exception)
            {

            }
        }

        #region Event Handlers
        protected void OnStart(string s)
        {
            // cancel the 'waiting' flag
            waitingForGame = false;
            
            // parse the start message
            string[] start = s.Split(null);

            board = start[0];
            time = Int32.Parse(start[1]);
            opponentName = start[2];
            
            // fire the GameStarted event
            if (GameStarted != null)
            {
                GameStarted(this, new StringEventArgs(s));
            }
        }

        protected void OnStop(string s)
        {
            // fire the GameStopped event
            if (GameStopped != null)
            { 
                GameStopped(this, new StringEventArgs(s));
            }
        }

        protected void OnScoreChanged(string s)
        {
            // parse the scores
            string[] scores = s.Split(null);

            // update each player's score
            score1 = Int32.Parse(scores[0]);
            score2 = Int32.Parse(scores[1]);

            // fire the ScoreChanged event
            if (ScoreChanged != null)
            {
                ScoreChanged(this, new StringEventArgs(s));
            }
        }

        protected void OnTime(string s)
        {
            // update the remaining time
            time = Int32.Parse(s);

            // fire the TimeChanged event
            if (TimeChanged != null)
            { 
                TimeChanged(this, new StringEventArgs(s));
            }
        }

        protected void OnTerminated()
        {
            if (Terminated != null)
            {
                Terminated(this, null);
            }
        }

        protected void OnIgnoring(string s)
        {
            if (Ignored != null)
            {
                Ignored(this, new StringEventArgs(s));
            }
        }

        protected void OnConnectionClosed()
        {
            // Fire the ConnectionClosed event
            if (ConnectionClosed != null)
            {
                ConnectionClosed(this, null);
            }
        }
        #endregion

    }
}
